#include <iostream>
#include <functional>
#include <memory>
#include <vector>
#include <unordered_map>
#include <unistd.h>
// 时间轮思想:我们定义了⼀个数组，并且有⼀个指针，指向数组起始位置，这个指针每秒钟向后
// 走动⼀步，走到哪⾥，则代表哪⾥的任务该被执行了，那么如果我们想要定⼀个3s后的任务，则只需
// 要将任务添加到tick+3位置，则每秒中走⼀步，三秒钟后tick⾛到对应位置，这时候执行对应位置的任务即可。

// 但是，同⼀时间可能会有⼤批量的定时任务，因此我们可以给数组对应位置下拉⼀个数组，这样就可以在同⼀个时刻上添加多个定时任务了。
// 采用多层级的时间轮，有秒针轮，分针轮，时针轮， 60<time<3600则time/60就是分针轮对应存储的位置，当tick/3600等于对应位置的时候，将其位置的任务向分针，秒针轮进⾏移动。

//当前的设计是时间到了，则主动去执行定时任务，释放连接，那能不能在时间到了后，自动执行定时任务呢，这时候我们就想到⼀个操作-类的析构函数。
//⼀个类的析构函数，在对象被释放时会自动被执⾏，那么我们如果将⼀个定时任务作为⼀个类的析构函数内的操作，则这个定时任务在对象被释放的时候就会执行。

// 用到了智能指针shared_ptr，shared_ptr有个计数器，当计数为0的时候，才会真正释放⼀个对象，那么如果连接在第10s进⾏了⼀次通信，则我们继续向定时任务中，添加⼀个30s后（也就是第40s）的任务类对象的shared_ptr，则这时候两个任务shared_ptr计数为2，则第30s的定时任务
// 被释放的时候，计数-1，变为1，并不为0，则并不会执行实际的析构函数，那么就相当于这个第30s的任务失效了，只有在第40s的时候，这个任务才会被真正释放。

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimerTask
{
public:
    TimerTask(uint64_t id,uint32_t delay,const TaskFunc & cb):
    _id(id),_timeout(delay),_task_cb(cb),_canceled(false){}
    ~TimerTask()
    {
        if(!_canceled) _task_cb();
        _release();
    }

    //取消定时任务
    void Cancel()
    {
        _canceled = true;
    }

    //设置对时间轮的操作
    void SetRelease(const ReleaseFunc & cb)
    {
        _release = cb;
    }

    //获取任务超时时间
    uint32_t DelayTime()
    {
        return _timeout;
    }
private:
    uint64_t _id;//定时器任务对象id
    uint32_t _timeout; //定时任务超时时间
    bool _canceled;//false表示没有取消定时任务,true表示取消了定时任务
    TaskFunc _task_cb;//定时器对象要执行的定时任务
    ReleaseFunc _release;//用于删除时间轮中保存的定时器对象信息
};

//时间轮
class TimerWheel
{
public:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    TimerWheel():
    _capacity(60),_tick(0),_wheel(_capacity){}
    //添加定时任务
    void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc & cb)
    {
        PtrTask pt(new TimerTask(id,delay,cb));
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));
        int pos = (_tick+delay)%_capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }

    //刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        std::unordered_map<uint64_t,WeakTask>::iterator it= _timers.find(id);
        if(it == _timers.end())
        {
            return;//没有定时任务,直接返回
        }
        //找到对应id的定时任务
        PtrTask pt = it->second.lock();//获取weak_ptr的shared_ptr
        uint32_t delay = pt->DelayTime();//获取延迟时间
        int pos = (_tick+delay)%_capacity;
        _wheel[pos].push_back(pt);
    }

    //取消定时任务
    void TimerCancel(uint64_t id)
    {
        std::unordered_map<uint64_t,WeakTask>::iterator it = _timers.find(id);
        if(it == _timers.end())
        {
            return;//没有对应的定时任务
        }
        PtrTask pt = it->second.lock();//获取weak_ptr的shared_ptr
        if(pt) pt->Cancel();
    }

    //让指针移动到下一步
    void RunTimerTask()
    {
        _tick = ++_tick%_capacity;
        _wheel[_tick].clear();//清空指定位置的数组,就会把数组中保存的所有对象释放,进行析构函数调用
    }
private:
    void RemoveTimer(uint64_t id)
    {
        std::unordered_map<uint64_t,WeakTask>::iterator it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(it);
        }
    }
private:
    int _tick;//当前的指针,表示指向的位置,指向哪里,就释放哪里
    int _capacity;//表盘的最大数量(最大延迟时间)
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t,WeakTask> _timers;
};

class Test
{
public:
    Test()
    {
        std::cout<<"构造函数"<<std::endl;
    }
    ~Test()
    {
        std::cout<<"析构函数"<<std::endl;
    }
};

void DelTest(Test * t)
{
    delete t;
}

int main()
{
    //创建时间轮
    TimerWheel tw;
    Test * t = new Test();
    tw.TimerAdd(111,5,std::bind(DelTest,t));
    for(int i = 0;i<5;i++)
    {
        sleep(1);
        tw.TimerRefresh(111);//刷新定时任务
        tw.RunTimerTask();//向后移动指针
        std::cout<<"刷新定时任务,重新等待5秒后执行"<<std::endl;
    }
    tw.TimerCancel(111);
    while(true)
    {
        sleep(1);
        std::cout<<"----------------------"<<std::endl;
        tw.RunTimerTask();
    }
    return 0;
}